package xj.toolkit.netty.initializer;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;

import java.security.KeyStore;
import java.util.List;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.lang3.StringUtils;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;

/**
 * JKS存储客户端证书+客户端秘钥。
 * 
 * @author <a href="mailto:cxj2000@gmail.com">xiaojian.cao</a>
 *
 */
public abstract class TcpClientInitializer extends SslBaseInitializer {
	private List<ChannelHandler> otherHandlers = Lists.newArrayList();

	protected void addCodecHandler(ChannelPipeline pipeline) throws Exception {
		pipeline.addLast("tcpRequestEncoder", getTcpRequestEncoder()).addLast("tcpResponseDecoder",
				getTcpResponseDecoder());
	}

	@Override
	protected void addBusinessHandler(ChannelPipeline pipeline) throws Exception {
		if (otherHandlers == null || otherHandlers.size() == 0) {
			return;
		}

		for (ChannelHandler handler : otherHandlers) {
			pipeline.addLast(handler.toString(), handler);
		}
	}

	@Override
	public void initChannel(Channel ch) throws Exception {
		if (isUseSsl()) {
			if (getKeyStoreResource() == null || !getKeyStoreResource().exists()) {
				throw new Exception("Pls set keyStore file.");
			}

			if (StringUtils.isBlank(getPassword())) {
				throw new Exception("Pls set password.");
			}

			KeyStore keyStore = KeyStore.getInstance("JKS");
			keyStore.load(getKeyStoreResource().getInputStream(), getPassword().toCharArray());
			TrustManagerFactory tf = TrustManagerFactory.getInstance("SunX509");
			tf.init(keyStore);
			
			SslContextBuilder sslContextBuilder = SslContextBuilder.forClient().trustManager(tf);
			
			if (isClientNeedAuth()) {
				KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
				keyManagerFactory.init(keyStore, getPassword().toCharArray());
				sslContextBuilder.keyManager(keyManagerFactory);
			}
			
			SslContext sslContext = sslContextBuilder.build();
			
			SSLEngine engine = sslContext.newEngine(ch.alloc());
			engine.setUseClientMode(true);
			ch.pipeline().addFirst("ssl", new SslHandler(engine));
		}

		super.initChannel(ch);
	}

	public abstract ChannelHandler getTcpResponseDecoder();

	public abstract ChannelHandler getTcpRequestEncoder();

	public void addOtherHandler(ChannelHandler otherHandler) {
		Preconditions.checkArgument(otherHandler != null);
		otherHandlers.add(otherHandler);
	}
}
